package com.apanal.qlife.common.shiro.realm;

import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;

import com.apanal.qlife.common.constants.Constants;
import com.apanal.qlife.common.exception.OrgDisableException;
import com.apanal.qlife.org.model.Organization;
import com.apanal.qlife.org.service.OrganizationService;
import com.apanal.qlife.sys.model.User;
import com.apanal.qlife.sys.service.ResourceService;
import com.apanal.qlife.sys.service.RoleService;
import com.apanal.qlife.sys.service.UserService;

/**
 * 
 * Shiro User Realm
 * 
 * @author shuliangxing
 * 
 * @date 2015-7-13下午6:08:33
 */
public class UserRealm extends AuthorizingRealm {

	@Autowired
	private UserService userService;

	@Autowired
	private RoleService roleService;

	@Autowired
	private ResourceService resourceService;

	@Autowired
	private OrganizationService OrganizationService;

	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(
			PrincipalCollection principals) {
		String username = (String) principals.getPrimaryPrincipal();
		User user = userService.findByUsername(username);

		SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
		authorizationInfo.setRoles(roleService.findNamesByUser(user));
		authorizationInfo.setStringPermissions(resourceService
				.findPermissionsByUser(user));
		return authorizationInfo;
	}

	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(
			AuthenticationToken token) throws AuthenticationException {
		// 登录账号
		String loginAccount = (String) token.getPrincipal();
		Object credentials = token.getCredentials();
		// 密码
		String password = credentials == null ? null : new String(
				(char[]) credentials);

		if (loginAccount == null || "".equals(loginAccount)) {
			throw new UnknownAccountException();
		}
		if (password == null || "".equals(password)) {
			throw new IncorrectCredentialsException();
		}

		User user = userService.findByMobile(loginAccount);
		// 如果身份验证失败请捕获AuthenticationException或其子类，常见的如：
		// DisabledAccountException（禁用的帐号）、LockedAccountException（锁定的帐号）、UnknownAccountException（错误的帐号）、ExcessiveAttemptsException（登录失败次数过多）、
		// IncorrectCredentialsException（错误的凭证）、ExpiredCredentialsException（过期的凭证）等
		if (user == null) {
			throw new UnknownAccountException();// 没找到帐号
		}

		if (Constants.LOCKED_TRUE.equals(user.getUseLocked())) {
			throw new LockedAccountException(); // 帐号锁定
		}

		Organization org = new Organization();
		org.setOrgId(user.getOrgId());
		org = OrganizationService.findOrganizationById(org);
		if (Constants.LOCKED_FALSE.equals(org.getNormal())) {
			throw new OrgDisableException(); // 机构停用,机构直属账号限制登录
		}

		// 交给AuthenticatingRealm使用CredentialsMatcher进行密码匹配，如果觉得人家的不好可以自定义实现
		SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
				user.getUseName(), // 用户名
				user.getUsePassword(), // 密码
				null,// ByteSource.Util.bytes(user.getCredentialsSalt()),//salt=username+salt
				getName() // realm name
		);
		return authenticationInfo;
	}

	@Override
	public void clearCachedAuthorizationInfo(PrincipalCollection principals) {
		super.clearCachedAuthorizationInfo(principals);
	}

	@Override
	public void clearCachedAuthenticationInfo(PrincipalCollection principals) {
		super.clearCachedAuthenticationInfo(principals);
	}

	@Override
	public void clearCache(PrincipalCollection principals) {
		super.clearCache(principals);
	}

	public void clearAllCachedAuthorizationInfo() {
		getAuthorizationCache().clear();
	}

	public void clearAllCachedAuthenticationInfo() {
		getAuthenticationCache().clear();
	}

	public void clearAllCache() {
		clearAllCachedAuthenticationInfo();
		clearAllCachedAuthorizationInfo();
	}

}
